package com.example.base_model.ext

import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import androidx.lifecycle.Lifecycle
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter

/**
 * @Author: jiangKunKun
 * @CreateDate: 2025/10/7
 * @Description: EditText 的扩展函数，将其文本变化转换为一个与生命周期感知的、可防抖的 Flow。
 * @SpittingGrooves:
 */

// @OptIn(FlowPreview::class) 注解说明：
// 1. 标记使用了 Kotlin Coroutines 的预览级 API。
// 2. `debounce` 操作符在早期版本中属于预览功能，其 API 可能会发生变化。
// 3. 使用此注解明确表示开发者了解并接受使用实验性功能的风险。
// 4. 避免编译器产生 "This is a preview API" 的警告信息。
@OptIn(FlowPreview::class)
/**
 * 将 EditText 的文本变化转换为一个 Flow<String>。
 *
 * 这个 Flow 会在 EditText 的文本发生任何改变时发射新的文本字符串。
 * 它利用了 `callbackFlow` 来将基于回调的 `TextWatcher` API 转换为响应式的 Flow。
 *
 * @receiver EditText 要监听的输入框。
 * @param lifecycle 关联的生命周期，用于自动管理数据流的发射。Flow 只会在生命周期至少处于 STARTED 状态时才发射数据。
 * @param debounceMs 防抖时间（毫秒）。在用户停止输入指定时长后，才会发射最新的文本。这对于避免因快速连续输入而触发过多操作非常有用（例如，网络搜索）。默认为 0，表示不进行防抖。
 * @param emitInitialValue 是否在 Flow 创建时立即发射一次当前的文本值。默认为 false。
 * @return 一个发射 EditText 文本变化的 Flow<String>。
 */
fun EditText.textChangesAsFlow(
    lifecycle: Lifecycle,
    debounceMs: Long = 0,
    emitInitialValue: Boolean = false
): Flow<String> = callbackFlow {
    // 1. 创建一个 TextWatcher 来监听文本变化
    val textWatcher = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        override fun afterTextChanged(editable: Editable?) {
            // 2. 文本变化后，通过 trySend 将新文本发送到 Flow 中。
            //    trySend 是非阻塞的，如果 Flow 的消费者跟不上，它会丢弃数据。
            trySend(editable.toString())
        }
    }

    // 3. 将 TextWatcher 添加到 EditText。
    addTextChangedListener(textWatcher)

    // 4. 可选：如果 emitInitialValue 为 true，则立即发送 EditText 的当前文本。
    if (emitInitialValue) {
        trySend(text.toString())
    }

    // 5. 使用 awaitClose 注册一个回调，当 Flow 被消费者取消或关闭时，这个回调会被执行。
    //    在这里，我们移除 TextWatcher，以防止内存泄漏。
    awaitClose {
        removeTextChangedListener(textWatcher)
    }
}
    // 6. debounce 操作符：防抖动处理。
    //    - 只有在指定的 debounceMs 毫秒内没有新的文本变化时，才会发射最新的文本。
    //    - 这可以有效防止因用户快速输入而导致的频繁事件处理。
    .debounce(debounceMs)
    // 7. filter 操作符：根据生命周期进行过滤。
    //    - 确保只有当关联的生命周期组件（如 Activity/Fragment）至少处于 STARTED 状态时，Flow 才会发射数据。
    //    - 这样可以避免在界面不可见时（如在后台）处理 UI 更新，防止不必要的工作和潜在的崩溃。
    .filter { lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) }
